// nodejs核心模块，直接使用
const os = require('os');
// cpu核数
const threads = os.cpus().length;
console.log('threads', threads)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 访问内置的插件
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
// css使用link单独打包成一个文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin"); //压缩js
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); //压缩图片
const WorkboxPlugin = require('workbox-webpack-plugin');
function getStyleLoader(pre) {
	return [
		MiniCssExtractPlugin.loader,
		'css-loader',
		{
			loader: "postcss-loader",
			options: {
				postcssOptions: {
					plugins: [
						"postcss-preset-env", // 能解决大多数样式兼容性问题
					],
				},
			},
		},
		pre
	].filter(Boolean)
}
module.exports = {
	// 入口 ：相对路径 是相对运行代码的目录
	entry: './src/main.js',
	//   出口：绝对路径
	// webpack2024/dist/main.js
	output: {
		//bug原因：出口路径错误

		// 入口文件打包输出文件名
		filename: 'static/js/[name].[contenthash:10].js',
		// 文件输出路径 生产模式需要输出
		// path: undefined,
		path: path.resolve(__dirname, '../dist'),
		chunkFilename: 'static/js/[name].chunk.[contenthash:10].js', // // 给打包输出的其他文件命名,name是webpackChunkName或者node_modules中打包文件名

		// 图片、字体等通过type:asset处理资源命名方式
		assetModuleFilename: "static/media/[hash:10][ext][query]",
		// 自动清空上次打包内容 原理：在打包前，将path整个目录内容清空，再进行打包
		clean: true,
	},
	module: {
		rules: [
			// 每个文件只能被一个loader处理
			{
				oneOf: [
					// {
					// 	test: /\.(js|jsx)$/,
					// 	use: 'babel-loader',
					// },
					// css-loader将css打包到js中；style-loader创建style标签，添加到html中生效
					// MiniCssExtractPlugin.loader 打包时提取css为单独的文件 （默认将所有css文件打包成一个css文件），通过 link 标签加载
					{
						test: /\.css$/,
						use: getStyleLoader()
					},
					{
						test: /\.less$/,
						// loader: 'xxx', // 只能使用1个loader
						use: getStyleLoader('less-loader')
					},
					{
						test: /\.s[ac]ss$/,
						use: getStyleLoader('sass-loader')
					},
					{
						test: /\.styl$/,
						use: getStyleLoader('stylus-loader')
					},
					// 搜索inline inlining asset
					{
						test: /\.(png|jpe?g|gif|webp|svg)$/,
						// 文件小于某个大小转化为base64
						type: 'asset',
						parser: {
							dataUrlCondition: {
								// 小于10kb的图片转base64
								// 优点：减少请求数量  缺点：体积会更大
								maxSize: 10 * 1024 // 10kb
							}
						},
						// 形成文件名字
						// ext:文件扩展名 query：携带参数
						//  [hash:10] hash值取前10位
						generator: {
							filename: 'static/images/[hash:10][ext][query]'
						},
						// 在这里配置图片压缩
						// minimize: true,
					},
					{
						// test: /\.(ttf|woff2?)$/,
						test: /\.(ttf|woff2?|map4|map3|avi)$/,
						// 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现 不压缩
						type: 'asset/resource',
						// generator: {
						// 	filename: 'static/media/[hash:10][ext][query]'
						// }
					},
					{
						test: /\.js$/,
						exclude: /(node_modules|bower_components)/,
						// exclude: /node_modules/, // 排除node_modules代码不编译
						// include: path.resolve(__dirname, "../src"), // 只处理src下的文件，其他文件不处理
						use: [
							{
								loader: "babel-loader",
								// 也可以在babel.config.js中配置
								options: {
									// presets: ['@babel/preset-env']
									cacheDirectory: true, // 开启babel编译缓存
									cacheCompression: false, // 缓存文件不要压缩
									plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
								},
							},
							{
								loader: "thread-loader", // 开启多进程
								options: {
									workers: threads, // 数量
								},
							},
						]
					},
				]
			}

		],
	},

	plugins: [
		new ESLintPlugin({
			// 检测文件所在的路径
			context: path.resolve(__dirname, '../src'),
			exclude: "node_modules", // 默认值
			cache: true, // 开启缓存
			// 缓存目录
			cacheLocation: path.resolve(
				__dirname,
				"../node_modules/.cache/.eslintcache"
			),
			threads, // 开启多进程
		}),
		new HtmlWebpackPlugin({
			// 以 public/index.html 为模板创建文件
			// 新的html文件有两个特点：1. 内容和源文件一致 2. 自动引入打包生成的js等资源
			template: path.resolve(__dirname, "../src/public/index.html"),
		}),
		new MiniCssExtractPlugin({
			filename: 'static/css/[name].[contenthash:10].css',
			// js中动态引入css命名
			chunkFilename: "static/css/[name].chunk.[contenthash:10].css",
		}),
		new WorkboxPlugin.GenerateSW({
			// 这些选项帮助快速启用 ServiceWorkers
			// 不允许遗留任何“旧的” ServiceWorkers
			clientsClaim: true,
			skipWaiting: true,
		}),
		// new CssMinimizerPlugin()
	],
	// 优化
	optimization: {
		minimize: true,
		minimizer: [
			// css压缩也可以写到optimization.minimizer里面，效果一样的
			new CssMinimizerPlugin(),
			// 当生产模式会默认开启TerserPlugin，但是我们需要进行其他配置，就要重新写了
			new TerserPlugin({
				parallel: threads // 开启多进程
			}),
			// 压缩图片
			new ImageMinimizerPlugin({
				minimizer: {
					implementation: ImageMinimizerPlugin.imageminGenerate,
					options: {
						plugins: [
							["gifsicle", { interlaced: true }],
							["jpegtran", { progressive: true }],
							["optipng", { optimizationLevel: 5 }],
							[
								"svgo",
								{
									plugins: [
										"preset-default",
										"prefixIds",
										{
											name: "sortAttrs",
											params: {
												xmlnsOrder: "alphabetical",
											},
										},
									],
								},
							],
						],
					},
				},
			}),

		],
		// 代码分割配置
		splitChunks: {
			chunks: "all",
			// 其他都用默认值
		},
		// 提取runtime文件,A文件依赖B文件，当B修改时，runtime文件修改，A文件不修改
		// entrypoint.name 入口文件名
		runtimeChunk: {
			name: (entrypoint) => `runtime~${entrypoint.name}.js`,
		},
	},
	// 开发服务器  注意这里的版本："webpack-dev-server": "^4.8.1"
	// 开发服务器: 不会输出资源，在内存中编译打包的
	// 生成模式不需要devServer，只需要打包输出文件
	// devServer: {
	// 	host: "localhost", // 启动服务器域名
	// 	port: "3000", // 启动服务器端口号
	// 	open: true, // 是否自动打开浏览器
	// },
	mode: 'production',
	devtool: "source-map"
}